package com.coffee.dict;

import cn.hutool.core.util.StrUtil;
import com.coffee.dict.annotation.CoffeeDictMap;
import com.coffee.dict.annotation.CoffeeDictMapAspect;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author songkui
 * @since 2019/5/8
 */
@Aspect
@AllArgsConstructor
@Slf4j
public class DictMapAspect implements PriorityOrdered {

    private final CoffeeDictCache coffeeDictCache;

    /**
     * 切入点，所有具有dictMap的方法
     */
    @Pointcut("@annotation(coffeeDictMapAspect)")
    public void dictMapPoint(CoffeeDictMapAspect coffeeDictMapAspect) {
    }

    /**
     * 环绕通知方式，拦截方法返回值并进行翻译后返回
     *
     * @param pjp
     * @param coffeeDictMapAspect
     * @return 翻译后的值
     * @throws Throwable
     */
    @Around("@annotation(coffeeDictMapAspect)")
    public Object translationAround(final ProceedingJoinPoint pjp, CoffeeDictMapAspect coffeeDictMapAspect) throws Throwable {
        Object result = pjp.proceed();
        if (null == result) {
            log.info("DictMapAspect result object is null");
            return null;
        }
        log.info("DictMapAspect start dict  translation... ");

        if (null == coffeeDictMapAspect || null == coffeeDictMapAspect.value() || coffeeDictMapAspect.value().length == 0) {
            log.info("Not translatedict: CoffeeDictMapAspect is null or coffeeDictMapAspect value is null");
            return result;
        }

        //check list
        if (result instanceof List) {
            List olist = (List) result;
            if (olist.isEmpty()) {
                return result;
            } else {
                Object obj = olist.get(0);
                if (obj != null && !(obj instanceof Map)) {
                    log.warn("Not translatedict: List data not Map; list data: {}", obj.getClass());
                    return result;
                }
            }
        }

        //do translation
        List<DictDataDetail> dictMapping = getDictMapping(coffeeDictMapAspect.value());
        if (result instanceof List) {
            for (Map entity : (List<Map>) result) {
                assign(entity, dictMapping);
            }
        } else {
            assign((Map) result, dictMapping);
        }

        return result;

    }


    /**
     * 翻译方法
     * <p>按照{@code dictMapping}中的目录参数信息，将{@code entity}中的字段翻译</p>
     *
     * @param entity      需要翻译的对象
     * @param dictMapping 具体字段翻译的配置
     */
    private void assign(Map entity, List<DictDataDetail> dictMapping) {
        for (DictDataDetail dictDataDetail : dictMapping) {
            String dictName = dictDataDetail.getSourceField();
            String targetField = dictDataDetail.getTargetField();
            if (StrUtil.isBlank(targetField)) {
                targetField = dictName + "Name";
            }

            String nullValue = dictDataDetail.getNullValue();
            String undefinedValue = dictDataDetail.getDefinedValue();
            Map<String, String> dictMap = dictDataDetail.getDictDetail();
            Object preValueObj = entity.get(dictDataDetail.getSourceField());

            if (ObjectUtils.isEmpty(preValueObj)) {
                entity.put(targetField, nullValue);
            } else {
                String preValue = preValueObj.toString().trim();
                if (dictDataDetail.getMultiple()) {
                    StringBuilder buffer = new StringBuilder();
                    String[] vs = preValue.split(",");
                    for (String v : vs) {
                        String name = dictMap.get(v);
                        buffer.append(name == null ? undefinedValue : name).append(",");
                    }
                    entity.put(targetField, buffer.deleteCharAt(buffer.length() - 1).toString());
                } else {
                    String name = dictMap.get(preValue);
                    entity.put(targetField, name == null ? undefinedValue : name);
                }
            }
        }

    }


    /**
     * 收集类中的字典翻译目录信息
     *
     * @param mappers 要收集的类型
     * @return 定义的字典目录信息
     */
    private List<DictDataDetail> getDictMapping(CoffeeDictMap[] mappers) {
        List<DictDataDetail> list = new ArrayList<>(mappers.length);
        for (CoffeeDictMap mapper : mappers) {
            //收集字典翻译参数信息
            Map<String, String> dictDetail = coffeeDictCache.dictMapByName(mapper.dictName());
            if (dictDetail.isEmpty()) {
                throw new NullPointerException("CoffeeDict not configuration [dictName: " + mapper.dictName() + "]");
            }
            DictDataDetail dictDataDetail = new DictDataDetail(mapper, dictDetail);
            list.add(dictDataDetail);
        }
        return list;
    }


    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
}
